//
// Created by chaseaishang on 23-4-10.
//
#include "Render/Renderer.h"
#include "Game1.h"
#include "imgui.h"
#include "Event.h"
#include "KeyEvent.h"



#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "ResourceManager.h"
#include "Input.h"
#include "GameTools/utils.h"

test::Game1::~Game1() {

}
const glm::vec2 PLAYER_SIZE(100, 20);
// 初始化当班的速率
const float PLAYER_VELOCITY(20.0f);

// 初始化球的速度
const glm::vec2 INITIAL_BALL_VELOCITY(100.0f, -350.0f);
// 球的半径
const float BALL_RADIUS = 12.5f;
test::Game1::Game1()
        :Width(800),Height(600),succeed(false),
         m_Proj(glm::ortho(0.0f, 800.0f, 600.0f, 0.0f, -1.0f, 1.0f)),
         m_View(glm::translate(glm::mat4(1.0f), glm::vec3(0, 0, 0))),
         m_TranslationA(glm::vec3(200, 200, 0)), m_TranslationB(glm::vec3(400, 200, 0)),
         m_rotate(0)
{
    //web
    char message[50];int len=0;
    m_portocol=std::make_unique<Portocol>();
    m_portocol->init();

    game_state state=game_state::GETREADY;
    GameData::packData(message,len,state, nullptr);
    m_portocol->sendToServer(message,len,state);
    state=m_portocol->recvFromServer(message,len, nullptr);
    if(state==game_state::GETREADY)
    {
        master=message[1];
    }
    //game and render

    m_SpriteRenderer=std::make_unique<SpriteRenderer>("../res/shaders/sprite.vs","../res/shaders/sprite.fs");
    auto ins=ResourceManager::get_instance();
    ins->LoadTexture("../res/textures/block.png","block");
    ins->LoadTexture("../res/textures/block_solid.png","block_solid");
    ins->LoadTexture("../res/textures/paddle.png","paddle");
    ins->LoadTexture("../res/textures/background.jpg","background");
    ins->LoadTexture("../res/textures/awesomeface.png","ball");
    m_SpriteRenderer->Set_viewProjection(m_Proj);
    //
    glm::vec2 playerPos = glm::vec2(
            this->Width / 4 - PLAYER_SIZE.x / 2,
            this->Height - PLAYER_SIZE.y
    );

    glm::vec2 other_playerPos = glm::vec2(
            this->Width / 4*3 - PLAYER_SIZE.x / 2,
            this->Height - PLAYER_SIZE.y
    );
    glm::vec3 masterColor(1.0,0.6,1.0);
    glm::vec3 otherColor(0.0,1.0,1.0);
    Player=std::make_unique<GameObject>(playerPos, PLAYER_SIZE, ins->GetTexture("paddle"),masterColor);
    other_Player=std::make_unique<GameObject>(other_playerPos,PLAYER_SIZE,ins->GetTexture("paddle"),otherColor);
    glm::vec2 ballPos = playerPos + glm::vec2(PLAYER_SIZE.x / 2 - BALL_RADIUS, -BALL_RADIUS * 2);
    Ball=std::make_unique<BallObject>(ballPos, BALL_RADIUS, INITIAL_BALL_VELOCITY,ins->GetTexture("ball"));

    // 加载关卡
    GameLevel one; one.Load("../res/GameLevels/one.lvl", this->Width, this->Height * 0.5);

    this->Levels.push_back(one);
    int i=this->Levels.size();
    this->Level = 1-1;
    //get master
    if(master)
    {
        std::cout<<"I am the master\n";
    }
    else
    {
        std::cout<<"I am Not the master\n";
        glm::vec3 tempcolor=Player->Color;
        float temp=Player->Position.x;
        Player->Position.x=other_Player->Position.x;
        Player->Color=other_Player->Color;
        other_Player->Position.x=temp;
        other_Player->Color=tempcolor;
    }
    State=GameState::GAME_READY;

}
void test::Game1::OnEvent(Event &e)
{
    if(e.IsInCategory(EventCategory::EventCategoryApplication))
    {
        return;
    }
    EventDispatcher dispatcher(e);
    dispatcher.Dispatch<KeyPressedEvent>(
            [&](KeyPressedEvent&e)
            {

                return true;
            }
    );
    dispatcher.Dispatch<KeyReleasedEvent>(
            [&](KeyReleasedEvent&e)
            {

                return true;
            }
    );

}

void test::Game1::OnRender()
{
    GLCall(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
    GLCall(glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT));
    if(State==GameState::GAME_ACTIVE)
    {
        m_SpriteRenderer->DrawSprite(*ResourceManager::get_instance()->GetTexture("background"),glm::vec2(0, 0), glm::vec2(
                this->Width, this->Height), 0, glm::vec3(1,1,1));

        this->Levels[this->Level].Draw(*this->m_SpriteRenderer);
        Player->Draw(*m_SpriteRenderer);
        other_Player->Draw(*m_SpriteRenderer);
        Ball->Draw(*m_SpriteRenderer);
    }

    //m_SpriteRenderer->DrawSprite(*ResourceManager::get_instance()->GetTexture("block"),glm::vec2(0, 0), glm::vec2(53, 53), 45.0f, glm::vec3(1.0f, 1.0f, 0.0f));

}


void test::Game1::OnImGuiRender()
{
    ImGui::Text("Master= %d",(int)this->master);
    ImGui::Text("Ball Pos= %f",this->get_ball_pos_x());
    ImGui::Text("other_Pos= %f",this->get_other_pos_x());
    ImGui::InputInt("win",&this->win,1,2);
    ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);

}



void test::Game1::OnUpdate(float deltaTime)
{
    if(State==GameState::GAME_READY)
    {
        char message[50];
        int len;
        game_state state=game_state::ASKBEGIN;
        GameData::packData(message,len,state);
        m_portocol->sendToServer(message,len,state);
        state=m_portocol->recvFromServer(message,len, nullptr);
        if(state==game_state::UNBEGIN)
        {
            //std::cout<<"otherPlayNotReady!\n";
            usleep(5*1000);
            return;
        }
        else if(state==game_state::FIRSTINGAME)
        {
            std::cout<<"firstingame";
            this->State=GameState::GAME_ACTIVE;
            m_portocol->ready=false;
        }
        //send
    }
    else if(State==GameState::GAME_ACTIVE)
    {
        //recv and update

        //

        if(this->is_failed())
        {
            this->Reset();
        }
        if(succeed)
        {
            this->win=1;

        }
        GameData::In_gameData g_data;
        g_data.deltaTime=deltaTime;

        float master_deltaTime=deltaTime;

        if(Input::IsKeyPressedImpl(CSAS_KEY_A))
        {
            g_data.key_code=0;
            this->Player->Position.x-=PLAYER_VELOCITY;
            Player->Position.x=
                    glm::clamp(Player->Position.x,0.0f,float (this->Width-PLAYER_SIZE.x));
            if(Ball->Stuck&&master)
            {//PLAYER_SIZE.x / 2 - BALL_RADIUS
                Ball->Position.x-=PLAYER_VELOCITY;
                Ball->Position.x=
                        glm::clamp(Ball->Position.x,PLAYER_SIZE.x / 2- BALL_RADIUS,float (this->Width-PLAYER_SIZE.x/2));
            }

        }
        else if(Input::IsKeyPressedImpl(CSAS_KEY_D))
        {
            g_data.key_code=1;
            this->Player->Position.x+=PLAYER_VELOCITY;
            Player->Position.x=
                    glm::clamp(Player->Position.x,0.0f,float (this->Width-PLAYER_SIZE.x));
            if(Ball->Stuck&&master)
            {
                Ball->Position.x+=PLAYER_VELOCITY;
                Ball->Position.x=
                        glm::clamp(Ball->Position.x,PLAYER_SIZE.x / 2- BALL_RADIUS,float (this->Width-PLAYER_SIZE.x/2));
            }
            else if(Ball->Stuck&&!master)
            {
                Ball->Position.x=other_Player->Position.x/2-BALL_RADIUS;
            }
        }
        if(Input::IsKeyPressedImpl(CSAS_KEY_SPACE))
        {
            g_data.key_code=2;
            if(master)
            {
                Ball->Stuck= false;
            }

        }
        char message[50];
        int len;
        game_state state=game_state::INGAMEING;

        g_data.x_pos=Player->Position.x;
        GameData::packData(message,len,state,&g_data);
        m_portocol->sendToServer(message,len,state);



        g_data.x_pos=Player->Position.x;
        GameData::packData(message,len,state,&g_data);
        state=m_portocol->recvFromServer(message,len,&g_data);
        if(state==game_state::INGAMEING)
        {
            other_Player->Position.x=g_data.x_pos;
            if(!master)
            {
                master_deltaTime=g_data.deltaTime;
            }
            int key_kode=g_data.key_code;
            switch (key_kode)
            {
                case 0://a

                    break;
                case 1://d
                    break;
                case 2:
                    if(!master)
                    {//
                        Ball->Stuck= false;
                    }
                    break;

            }
            if(Ball->Stuck )
            {
                if(!master)
                {
                    int size=PLAYER_SIZE.x/2;
                    Ball->Position.x=other_Player->Position.x+size-BALL_RADIUS;
                }

            }

        }
        else if(state==game_state::QUIT)
        {
            this->win= 1;
        }
        //pos send

        Ball->Move(master_deltaTime,this->Width);
        this->DoCollisions();



        if(this->win)
        {
            State=GameState::GAME_WIN;
            game_state state=game_state::QUIT;
            GameData::packData(message,len,state, nullptr);
            m_portocol->sendToServer(message,len,state);
        }
    }
    else if(State==GameState::GAME_WIN)
    {
        //
    }


}

void test::Game1::DoCollisions()
{
    if(master)
    {
        Collision_Player_Ball(*Player,*Ball);
        Collision_Player_Ball(*other_Player,*Ball);
    }
    else
    {
        Collision_Player_Ball(*other_Player,*Ball);
        Collision_Player_Ball(*Player,*Ball);
    }


    for (GameObject &box : this->Levels[this->Level].Bricks)
    {
        if(!box.Destroyed)
        {
            G_utils::Collision collision = G_utils::CheckCollision(*Ball, box);
            if (std::get<0>(collision)) // 如果collision 是 true
            {
                // 如果砖块不是实心就销毁砖块
                if (!box.IsSolid)
                {
                    box.Destroyed = GL_TRUE;
                    succeed=this->Levels[this->Level].IsCompleted();
                }

                // 碰撞处理
                G_utils::Direction dir = std::get<1>(collision);
                glm::vec2 diff_vector = std::get<2>(collision);
                if (dir == G_utils::Direction::LEFT || dir == G_utils::Direction::RIGHT) // 水平方向碰撞
                {
                    Ball->Velocity.x = -Ball->Velocity.x; // 反转水平速度
                    // 重定位
                    GLfloat penetration = Ball->Radius - std::abs(diff_vector.x);
                    if (dir == G_utils::Direction::LEFT)
                        Ball->Position.x += penetration; // 将球右移
                    else
                        Ball->Position.x -= penetration; // 将球左移
                } else // 垂直方向碰撞
                {
                    Ball->Velocity.y = -Ball->Velocity.y; // 反转垂直速度
                    // 重定位
                    GLfloat penetration = Ball->Radius - std::abs(diff_vector.y);
                    if (dir == G_utils::Direction::UP)
                        Ball->Position.y -= penetration; // 将球上移
                    else
                        Ball->Position.y += penetration; // 将球下移
                }
            }
        }
    }


}

using namespace G_utils;
void test::Game1::Collision_Player_Ball(GameObject &Player, BallObject &Ball)
{
    Collision result = CheckCollision(Ball, Player);
    if (!Ball.Stuck && std::get<0>(result))
    {
        // 检查碰到了挡板的哪个位置，并根据碰到哪个位置来改变速度
        float centerBoard = Player.Position.x + Player.Size.x / 2;
        float distance = (Ball.Position.x + Ball.Radius) - centerBoard;
        float percentage = distance / (Player.Size.x / 2);
        // 依据结果移动
        float strength = 2.0f;
        glm::vec2 oldVelocity = Ball.Velocity;
        Ball.Velocity.x = INITIAL_BALL_VELOCITY.x * percentage * strength;
        Ball.Velocity.y = -1*std::abs(Ball.Velocity.y);
        //Ball->Velocity.y = -1 * abs(Ball->Velocity.y);
        Ball.Velocity = glm::normalize(Ball.Velocity) * glm::length(oldVelocity);
    }

}

bool test::Game1::is_failed() {

    return Ball->Position.y >= this->Height;
}

void test::Game1::Reset()
{

    Player->Size = PLAYER_SIZE;
    if(master)
    {
        Player->Position = glm::vec2(this->Width / 2 - PLAYER_SIZE.x / 2, this->Height - PLAYER_SIZE.y);
        Ball->Reset(Player->Position + glm::vec2(PLAYER_SIZE.x / 2 - BALL_RADIUS, -(BALL_RADIUS * 2)), INITIAL_BALL_VELOCITY);
    }
    else
    {
        other_Player->Position=glm::vec2(this->Width / 2 - PLAYER_SIZE.x / 2, this->Height - PLAYER_SIZE.y);
        Ball->Reset(other_Player->Position + glm::vec2(PLAYER_SIZE.x / 2 - BALL_RADIUS, -(BALL_RADIUS * 2)), INITIAL_BALL_VELOCITY);
    }

}

float test::Game1::get_ball_pos_x()
{

    return Ball->Position.x;
}

float test::Game1::get_other_pos_x() {
    return other_Player->Position.x;
}




